package ml.preprocessing;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

import ml.UpAndCountDownLatch;

import weka.attributeSelection.CfsSubsetEval;
import weka.attributeSelection.GreedyStepwise;
import weka.core.Instances;
import weka.filters.Filter;
import weka.filters.supervised.attribute.AttributeSelection;
import weka.core.converters.ConverterUtils.DataSource;

public class CFSFilter implements Runnable {

	private final UpAndCountDownLatch latch;
	private final String testPath;
	private final String trainPath;
	private final String testStorePath;
	private final String trainStorePath;

	public CFSFilter(UpAndCountDownLatch latch, String testPath,
			String trainPath, String testStorePath, String trainStorePath) {
		this.testPath = testPath;
		this.trainPath = trainPath;
		this.testStorePath = testStorePath;
		this.trainStorePath = trainStorePath;
		this.latch = latch;
	}

	@Override
	public void run() {
		latch.countUp();
		try {
			System.out.println("Filtering " + trainPath);
			DataSource ts = new DataSource(testPath);
			DataSource trs = new DataSource(trainPath);
			Instances test = ts.getDataSet();
			Instances train = trs.getDataSet();
			test.setClassIndex(test.numAttributes() - 1);
			train.setClassIndex(train.numAttributes() - 1);

			AttributeSelection filter = new AttributeSelection();
			cfsSubsetEvalFilter(train, filter);

			// apply filter
			train = Filter.useFilter(train, filter);
			test = Filter.useFilter(test, filter);

			// store filtered File
			storeArff(train, trainStorePath);
			storeArff(test, testStorePath);

		} catch (Exception e) {
			e.printStackTrace();
			return;
		} finally {
			latch.countDown();
		}

	}

	private static void cfsSubsetEvalFilter(Instances train,
			AttributeSelection filter) throws Exception {
		CfsSubsetEval eval = new CfsSubsetEval();
		GreedyStepwise search = new GreedyStepwise();

		// eval.setLocallyPredictive(true);
		// eval.setMissingSeparate(false);

		search.setSearchBackwards(true);
		// search.setThreshold(-1.7976931348623157E308);
		// search.setNumToSelect(-1);
		// search.setGenerateRanking(false);
		// search.setConservativeForwardSelection(false);

		filter.setEvaluator(eval);
		filter.setSearch(search);
		filter.setInputFormat(train);
	}

	private static void storeArff(Instances data, String path)
			throws IOException {
		BufferedWriter writer = new BufferedWriter(new FileWriter(path));
		writer.write(data.toString());
		writer.newLine();
		writer.flush();
		writer.close();
	}

}
